import {
  OnInit,
  Directive,
  TemplateRef,
  Input,
  EmbeddedViewRef,
  ViewContainerRef,
  OnChanges,
  SimpleChanges,
  OnDestroy,
} from '@angular/core';
import { AnimationBuilder, AnimationMetadata } from '@angular/animations';
import { Subject } from 'rxjs';

import { SlideType, SlideDirection, slideAnimation } from './tab-animation';

@Directive({
  selector: '[fuiTabPane]',
})
export class TabPaneDirective implements OnInit, OnChanges, OnDestroy {

  /** Tab pane title. */
  @Input('fuiTabPane') title: string;

  /** Optional tab pane template. */
  @Input('fuiTabPaneTemplate') titleTemplate: TemplateRef<any>;

  // TODO(0.7.0): fuiTabPaneIndex -> fuiTabPaneKey
  /**
   * Optional tab pane index. If not set, default index of tab pane will be used.
   */
  @Input('fuiTabPaneIndex') key: any;

  /**
   * Force reload tab pane if set true.
   * Tab's content will be destroyed when it's not active under this circumstance.
   */
  @Input() fuiTabPaneForceReload: boolean;

  viewRef: EmbeddedViewRef<TabPaneDirective>;

  visible = false;

  container: ViewContainerRef;

  active: boolean;

  animated: boolean;

  titleChangeSubj: Subject<string> = new Subject<string>();

  constructor(
    private template: TemplateRef<TabPaneDirective>,
    private animationBuilder: AnimationBuilder,
  ) { }

  ngOnInit() {
  }

  ngOnChanges(changes: SimpleChanges) {
    const {title: titleChange, titleTemplate: titleTemplateChange} = changes;
    if (titleChange && titleChange.previousValue || titleTemplateChange && titleTemplateChange.previousValue) {
      this.titleChangeSubj.next(titleChange.currentValue || titleTemplateChange.currentValue);
    }
  }

  /**
   * 初始化
   *
   * @param container 挂载container
   * @param index 如组件key未传入，则使用pane在tab中的序号作为key
   * @param animated 是否开启动画
   */
  init(container: ViewContainerRef, index: number, animated: boolean) {
    this.container = container;
    if (this.viewRef) {
      this.attachView();
    }
    if (this.key === undefined) {
      this.key = index;
    }
    this.animated = animated;
  }

  show(direction?: SlideDirection) {
    if (this.visible) {
      return;
    }

    this.visible = true;
    if (this.fuiTabPaneForceReload || !this.viewRef) {
      this.createView();
    } else {
      this.attachView();
    }

    if (direction && this.animated) {
      this.animate('in', direction);
    }
  }

  hide(direction?: SlideDirection) {
    if (!this.visible) {
      return;
    }

    this.visible = false;
    if (direction && this.animated) {
      this.animate('out', direction, () => {
        // 避免在移除view之前调用了show方法错误移除
        // 如果仍旧是隐藏状态则移除view。
        if (!this.visible) {
          this.onHide();
        }
      });
    } else {
      this.onHide();
    }
  }

  onHide() {
    if (this.fuiTabPaneForceReload) {
      this.clear();
    } else if (this.viewRef) {
      this.detachView();
    }
  }

  createView() {
    this.clear();
    this.viewRef = this.container.createEmbeddedView(this.template);
  }

  attachView() {
    // container里view应该只有一个，所以不需要带index
    if (this.container.length === 0) {
      this.container.insert(this.viewRef);
    }
  }

  detachView() {
    this.container.detach();
  }

  clear() {
    this.container.clear();
    this.viewRef = null;
  }

  animate(actionType: SlideType, slideDirectiion: SlideDirection, callback?: () => void) {
    const metadata: AnimationMetadata[] = slideAnimation(slideDirectiion, actionType);
    const factory = this.animationBuilder.build(metadata);
    const element = this.viewRef.rootNodes[0];
    const player = factory.create(element);
    player.play();

    if (callback) {
      player.onDone(callback);
    }
  }

  ngOnDestroy() {
    this.titleChangeSubj.complete();
  }
}
